using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.ComponentModel.DataAnnotations;
using System.Linq;
using System.Reflection;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Input;
using DotNet.Utilities;
using DotNet.Utilities.ConsoleHelper;
using DotNet.Utilities.Sql.SqlSugar;
using PropertyChanged;
using SqlSugar;
using WPFPractice.EntitySugar;
using WPFPractice.Models;
using WPFPractice.Utils;
using WPFPractice.ViewModels;
using WPFTemplateLib.Controls.WpfToast;
using WPFTemplateLib.WpfHelpers;

namespace WPFPractice.Windows
{
	public partial class WinDataGrid5 : Window
	{
		private WinDataGrid5ViewModel _vm;

		public WinDataGrid5()
		{
			InitializeComponent();
			DataContext = _vm = new WinDataGrid5ViewModel();

			_vm.SelectedItemChanged += OnSelectedItemChanged;
		}

		/// <summary>
		/// 选中项改变事件执行方法
		/// </summary>
		/// <param name="index">选中行索引</param>
		private void OnSelectedItemChanged(int index)
		{
			try
			{
				if(index >= 0)
				{
					Dg.ScrollIntoView(Dg.Items.GetItemAt(index));
				}
			}
			catch(Exception ex)
			{
				MessageBox.Show($"{ex}");
			}
		}

		private void EventSetter_LostFocus(object sender, RoutedEventArgs e)
		{
			var selected = _vm.SelectedItem;
			if(selected != null)
			{
				//selected.EditType = EditTypeEnum.Show;
			}
		}

		private void Dg_OnMouseDown(object sender, MouseButtonEventArgs e)
		{
			switch(sender)
			{
				//只在点击表格其它地方时执行某些操作，点击行时不处理;
				case DataGrid dg:
					//想要进行的操作写这里;

					MessageBox.Show("点击了表格空白处");

					//如果是自动列，使用此方法可以使选中的单元格进入编辑模式，但是不知道如何使整行进入编辑模式;
					dg.BeginEdit();

					break;
				case DataGridRow row:
					e.Handled = true; //标记为已处理，就不会触发之后的 DataGrid 的 MouseDown 事件;
					break;
				default:
					break;
			}
		}
	}
}

namespace WPFPractice.ViewModels
{
	[AddINotifyPropertyChangedInterface]
	public class WinDataGrid5ViewModel : MyViewModelBase
	{
		#region 成员

		/// <summary>
		/// 改变前的对象引用
		/// </summary>
		private User _originUser;

		private SqlSugarHelper _dbHelper;

		#endregion

		#region Bindable

		/// <summary>
		/// 表格数据
		/// </summary>
		public ObservableCollection<User> Datas { get; set; }

		/// <summary>
		/// 选中项改变事件
		/// </summary>
		public event Action<int> SelectedItemChanged;

		private User _SelectedItem;
		/// <summary>
		/// 选中项
		/// </summary>
		public User SelectedItem
		{
			get => _SelectedItem;
			set
			{
				SetProperty(ref _SelectedItem, value);

				SelectedItemChanged?.Invoke(Datas.IndexOf(_SelectedItem));
			}
		}

		private EditTypeEnum _editType = EditTypeEnum.Show;
		/// <summary>
		/// 编辑模式
		/// </summary>
		public EditTypeEnum EditType
		{
			get => _editType;
			set
			{
				_editType = value;
				ShowInfoUc($"切换到 {_editType.GetEnumDescription()}");
			}
		}

		/// <summary>
		/// 数据库连接配置
		/// </summary>
		public DbConnectPara DbConnectPara { get; set; } = new();

		/// <summary>
		/// 选中项集合（绑定于 Behavior）
		/// </summary>
		public IList SelectedItemsForBehavior { get; set; }

		/// <summary>
		/// 选中项集合（绑定于附加属性）
		/// </summary>
		public IList SelectedItemsForAttached { get; set; }

		/// <summary>
		/// 选中项集合信息
		/// </summary>
		public string SelectedItemsInfo { get; set; }

		#endregion

		#region Command

		/// <summary>
		/// 切换到新增模式命令
		/// </summary>
		public ICommand EnterAddModeCmd { get; set; }

		/// <summary>
		/// 添加用户命令
		/// </summary>
		public ICommand AddUserCmd { get; set; }

		/// <summary>
		/// 表格选择行变化事件触发命令
		/// </summary>
		public ICommand SelectionChangedCmd { get; set; }

		/// <summary>
		/// 是否能执行选择行变化命令
		/// </summary>
		public bool IsCanSelectionChanged { get; set; } = true;

		/// <summary>
		/// 删除命令
		/// </summary>
		public ICommand DeleteCmd { get; set; }

		/// <summary>
		/// 进入编辑模式命令
		/// </summary>
		public ICommand EnterEditCmd { get; set; }

		/// <summary>
		/// 失去焦点事件命令
		/// </summary>
		public ICommand LostFocusCmd { get; set; }

		/// <summary>
		/// 连接数据库命令
		/// </summary>
		public ICommand ConnectCmd { get; set; }

		/// <summary>
		/// 读取数据命令
		/// </summary>
		public ICommand ReadCmd { get; set; }

		/// <summary>
		/// 更新用户命令
		/// </summary>
		public ICommand UpdateUserCmd { get; set; }

		#region [命令] 选中项集合变动
		private RelayCommand<IList> _SelectedItemsChangedCmd;
		public RelayCommand<IList> SelectedItemsChangedCmd => _SelectedItemsChangedCmd ??= new RelayCommand<IList>(ExecuteSelectedItemsChangedCmd);
		private void ExecuteSelectedItemsChangedCmd(IList list)
		{
			if(list != null)
			{
				var names = list.Cast<User>().Select(x => x.UserName);
				SelectedItemsInfo = string.Join("、", names);
			}
			else
			{
				SelectedItemsInfo = String.Empty;
			}
		}
		#endregion

		#endregion

		public WinDataGrid5ViewModel()
		{
			Console.SetOut(new ConsoleWriter(s =>
			{
				ShowInfoUc(s);
			}));

			SetCommandMethod();

			_ = InitValueAsync();
		}

		/// <summary>
		/// 数据初始化
		/// </summary>
		private async Task InitValueAsync()
		{
			await Task.Yield();
			ShowInfoUc("演示 表格多选绑定");
			ShowInfoUc("演示 将垂直滚动条放在左边");
			ShowInfoUc("演示 列头显示上下箭头的排序标志");
		}

		/// <summary>
		/// 命令方法赋值(在构造函数中调用)
		/// </summary>
		private void SetCommandMethod()
		{
			EnterAddModeCmd ??= new RelayCommand(o => true, o =>
			{
				EditType = EditTypeEnum.Add;
				SelectedItem = new User();
			});

			ConnectCmd ??= new RelayCommand(o => true, o =>
			{
				try
				{
					var db = new SqlSugarClient
					(
						new ConnectionConfig()
						{
							ConnectionString = $"datasource={DbConnectPara.DbName}.db",
							DbType = DbType.Sqlite,
							IsAutoCloseConnection = true,
							ConfigureExternalServices = new ConfigureExternalServices
							{
								//[SQLSugar 对 String 类型空值的处理](https://gitee.com/dotnetchina/SqlSugar/issues/I56EZS)
								EntityService = (c, p) =>
								{
									// int?、decimal? 这种 isnullable=true
									if(c.PropertyType.IsGenericType && c.PropertyType.GetGenericTypeDefinition() == typeof(Nullable<>))
									{
										p.IsNullable = true;
									}
									else if(c.PropertyType == typeof(string) && c.GetCustomAttribute<RequiredAttribute>() == null)
									{ //string类型如果没有Required，isnullable=true
										p.IsNullable = true;
									}
								}
							}
						},
						db =>
						{
							db.Aop.OnLogExecuting = (sql, pars) =>
							{
								//获取原生SQL推荐 5.1.4.63  性能OK
								Console.WriteLine(UtilMethods.GetNativeSql(sql, pars));

								//获取无参数化SQL 对性能有影响，特别大的SQL参数多的，调试使用
								//Console.WriteLine(UtilMethods.GetSqlString(DbType.SqlServer,sql,pars))
							};
						}
					);

					_dbHelper = SqlSugarHelper.GetNewHelper(db);
					if(_dbHelper == null)
					{
						Console.WriteLine("创建数据库失败!");
						return;
					}

					//初始化表
					_dbHelper.Db.CodeFirst.InitTables<UserEntity>();

					ToastToScreenCmd.Execute("连接成功");
				}
				catch(Exception ex)
				{
					Console.WriteLine($"连接数据库时异常：{ex}");
				}
			});

			ReadCmd ??= new RelayCommand(o => _dbHelper != null, o =>
			{
				try
				{
					var userEntities = _dbHelper.Find<UserEntity>().ToList();
					if(userEntities.Any())
					{
						var users = userEntities.Select(e => ClassHelper.AutoMap<User, UserEntity>(e)).ToList();
						Datas = new(users);
						ToastToScreenCmd.Execute("读取成功");
					}
					else
					{
						Datas = TestDataHelper.GetUsers();
						var users = Datas.Select(u => ClassHelper.AutoMap<UserEntity, User>(u)).ToList();
						_dbHelper.UpdateOrInsert(users);
						ToastToScreenCmd.Execute("模拟数据写入数据库成功");
					}

					EditType = EditTypeEnum.Show;
				}
				catch(Exception ex)
				{
					Console.WriteLine($"读取数据时异常：{ex}");
				}
			});

			AddUserCmd ??= new RelayCommand(o => !string.IsNullOrEmpty(SelectedItem?.UserName), o =>
			{
				try
				{
					Datas.Add(SelectedItem);
					UserEntity entity = ClassHelper.AutoMap<UserEntity, User>(SelectedItem);
					var result = _dbHelper.UpdateOrInsert(new List<UserEntity> { entity });
					if(result.IsSuccess)
					{
						Console.WriteLine($"已添加用户 {SelectedItem.UserName}");
					}
					else
					{
						Console.WriteLine($"添加失败：{result.Message}");
						ToastToScreen("添加失败", ToastIcons.Error);
					}

					ReadCmd.Execute(null);
				}
				catch(Exception ex)
				{
					Console.WriteLine($"添加用户时异常：{ex}");
				}
			});

			UpdateUserCmd ??= new RelayCommand(o => !string.IsNullOrEmpty(SelectedItem?.UserName), o =>
			{
				try
				{
					UserEntity entity = ClassHelper.AutoMap<UserEntity, User>(SelectedItem);
					var result = _dbHelper.UpdateOrInsert(new List<UserEntity> { entity });
					if(result.IsSuccess)
					{
						ShowInfoUc($"已更新用户 {SelectedItem.UserName}");
					}
					else
					{
						Console.WriteLine($"更新用户[{SelectedItem.UserName}]时出错：{result.Message}");
					}

					ReadCmd.Execute(null);
				}
				catch(Exception ex)
				{
					Console.WriteLine($"更新用户时异常：{ex}");
				}
			});

			SelectionChangedCmd ??= new RelayCommand(o => IsCanSelectionChanged, o =>
			{
				try
				{
					IsCanSelectionChanged = false;

					var args = o as SelectionChangedEventArgs;
					EditType = EditTypeEnum.Show;

					if(_originUser != null)
					{
						_originUser.EditType = EditTypeEnum.Show;
					}
				}
				catch(Exception ex)
				{
					Console.WriteLine(ex);
				}
				finally
				{
					_originUser = SelectedItem;
					IsCanSelectionChanged = true;
				}
			});

			DeleteCmd ??= new RelayCommand(o => true, o =>
			{
				var user = o as User;
				if(user == null)
				{
					return;
				}

				Datas.Remove(user);
				UserEntity entity = ClassHelper.AutoMap<UserEntity, User>(user);
				_dbHelper.Delete(new List<UserEntity> { entity });
				ShowInfoUc($"已删除用户[{user.UserName}]");
				EditType = EditTypeEnum.Show;
			});

			EnterEditCmd ??= new RelayCommand(o => true, o =>
			{
				EditType = EditTypeEnum.Edit;
				if(SelectedItem != null)
				{
					SelectedItem.EditType = EditType;
				}
			});

			LostFocusCmd ??= new RelayCommand(o => true, o =>
			{
				var args = o as RoutedEventArgs;

				if(args.Source.GetType() == typeof(DataGrid) && SelectedItem != null)
				{
					//SelectedItem.EditType = EditTypeEnum.Show;
				}
			});
		}

		#region [命令] 在 VM 中控制排序
		private RelayCommand _SortInVmCmd;
		public RelayCommand SortInVmCmd => _SortInVmCmd ??= new RelayCommand(ExecuteSortInVmCmd);
		private void ExecuteSortInVmCmd()
		{
			var view = CollectionViewSource.GetDefaultView(Datas);
			view.SortDescriptions.Clear();
			view.SortDescriptions.Add(new SortDescription("Age", ListSortDirection.Descending));
			view.Refresh();
		}
		#endregion
	}
}
